#include <iostream>
#include <fstream>
#include <string>
#include "contacts.pb.h"

using namespace contacts;

void AddPeopleInfo(contacts::PeopleInof *peo)
{
    std::cout << "-------------新增联系⼈-------------" << std::endl;
    std::cout << "请输入要添加的联系人姓名: ";
    std::string name;
    std::getline(std::cin, name);
    peo->set_name(name);
    std::cout << "请输入联系人年龄: ";
    int age;
    std::cin >> age;
    peo->set_age(age);

    /**
     * cin.ignore(a,ch)函数的解释
     * 它表示从输入流 cin 中提取字符，提取的字符被忽略，不被使用
     * 而每抛弃一个字符，它都要进行计数和比较字符
     * 如果计数值达到 a 或者被抛弃的字符是 ch ，则cin.ignore() 函数执行终止；否则，它继续等待。
     */
    std::cin.ignore(256, '\n');
    for (int i = 0;; i++)
    {
        std::cout << "请输入联系人电话: " << i + 1 << "(只输入回车完成电话的新增): ";
        std::string number;
        std::getline(std::cin, number);
        if (number.empty())
            break;
        contacts::Phone *phone = peo->add_phone();
        phone->set_number(number);

        std::cout << "请选择输入该电话的类型(1.移动电话 2.固定电话):";
        int type;
        std::cin >> type;
        std::cin.ignore(256, '\n');//也是清除cin中的\n
        switch (type)
        {
        /**
         * set_type()函数-->void set_type(::contacts::Phone_PhoneType value);
         * 该函数表示的就是设置phone的电话类型
        */
        case 1:
            phone->set_type(contacts::Phone_PhoneType::Phone_PhoneType_MP);
            break;
        case 2:
            phone->set_type(contacts::Phone_PhoneType::Phone_PhoneType_TEL);
            break;
        default:
            std::cout << "请正确选择!" << std::endl;
            break;
        }
    }
    //添加联系人的地址信息
    contacts::Address address;
    std::cout << "请输入联系人的家庭地址:";
    std::string home_address;
    std::getline(std::cin,home_address);
    address.set_home_address(home_address);//设置联系人的家庭地址
    std::cout << "请输入联系人的单位地址:";
    std::string unit_address;
    std::getline(std::cin,unit_address);
    address.set_unit_address(unit_address);//设置联系人的单位地址
    //Address->Any
    peo->mutable_data()->PackFrom(address);//将我们的addres原本的Address类转化成我们的Any类

    //新增联系人的其他联系方式
    std::cout << "请选择需要额外添加的联系方式(1.qq  2.wechat 3.other) :";
    int other_contact;
    std::cin >> other_contact;
    std::cin.ignore(256,'\n');

    std::string qq,wechat;
    //使用的是switch-case主要模拟的是第三种情况
    //也就是使用oneof限制的条件下，也就是多种变量的时候只取最后一次的变量
    switch(other_contact)
    {
        case 1:
            std::cout << "请输入qq号码: ";
            getline(std::cin,qq);
            peo->set_qq(qq);
            break;
        case 2:
            std::cout << "请输入wechat号码: ";
            getline(std::cin,wechat);
            peo->set_wechat(wechat);
            break;
        case 3:
            std::cout << "请输入qq号码: ";
            getline(std::cin,qq);
            peo->set_qq(qq);
            std::cout << "请输入wechat号码: ";
            getline(std::cin,wechat);
            peo->set_wechat(wechat);
            break;
        default:
            std::cout << "选择有误,未成功添加其他联系方式! " << std::endl;
            break;
    }

    //使用map来添加联系人备注
    for(int i = 0; ; i++)
    {
        std::cout  << "请输入备注" << i + 1 << "标题(只输入回车完成备注新增):";
        std::string remake_key;
        std::getline(std::cin,remake_key);
        if(remake_key.empty()) break;
        std::cout << "请输入备注" << i + 1 << "内容: ";
        std::string remake_value;
        std::getline(std::cin,remake_value);
        peo->mutable_remake()->insert({remake_key,remake_value});
    }
    std::cout << "-----------添加联系⼈成功-----------" << std::endl;
}

int main()
{
    contacts::contacts contacts;
    // 1.读取本地存有的通讯录文件

    /**
     * 对于fstream in函数的说明
     * 1.该函数表示的是打卡文件"contacts.bin"
     * 2.采用的打开方式的binary也就是二进制的方法
     * 3.并且是读取的方式(std::ios::in)方式
     *
     * 对于函数contacts.ParseFromIstream(&in)的解答
     * 表示的是进行反序列化的操作，并且判断是否反序列化打开成功
     */
    std::fstream in("contacts.bin", std::ios::binary | std::ios::in);
    if (!in)
    {
        std::cout << "contacts.bin not find, create new file!" << std::endl;
    }
    else if (!contacts.ParseFromIstream(&in))
    {
        std::cerr << "parse error!" << std::endl;
        return -1;
    }
    // 2.像通讯录中添加联系人信息
    AddPeopleInfo(contacts.add_peo());
    // 3.当更改后的通讯录导入到本地文件中
    std::fstream out("contacts.bin", std::ios::binary | std::ios::out | std::ios::trunc);
    /**
     * SerializeToOstream()函数表示的是序列化操作
     * 因为要向文件中写入
     * 对应ParseFromIstream()函数(反序列化)
     */
    if (!contacts.SerializeToOstream(&out))
    {
        std::cerr << "write error!" << std::endl;
        in.close();
        out.close();
        return -1;
    }
    std::cout << "write success!" << std::endl;
    in.close();
    out.close();
    return 0;
}